
#include "ae.h"
#include "core.h"
#include "server.h"
#include "thread.h"
#include "zmalloc.h"

#include "mylog.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define INIT_THREADPOOL_ERROR	-1
#define INIT_THREADPOOL_SECC		0

static int initThreadPool(core* c) {
	if (!c) {
		mylog(LOG_WARNING,  "init thread poll error!!!");
		return INIT_THREADPOOL_ERROR;
	}

	int i;
	for (i = 0; i < c->workThreadNum; i++) {
		struct thread* t = initThread();
		c->workThreadList[i] = t;
	}

	mylog(LOG_INFO, "init Thread pool success!!!");
	return INIT_THREADPOOL_SECC;
}

static void destroyThreadPool(core* c) {
	if (!c) {
		mylog(LOG_WARNING, "destroy Thread pool error!!!");
		return;
	}

	int i;
	for (i = 0; i < c->workThreadNum; i++) {
		if (c->workThreadList[i]) {
			destroyThread(c->workThreadList[i]);
		}
	}

	mylog(LOG_INFO,  "destroy Thread pool success!!!");
	return;
}

int coreCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
	//mylog(LOG_INFO, "coreCron!!!");
	struct core* c = (struct core*) clientData;
	if (!c) {
		return AE_NOMORE;
	}

	if (c->coreStat == CORE_STAT_STOP) {
		mylog(LOG_INFO, "stop core!!!");
		if (c->eventLoop) {
			aeStop(c->eventLoop);
			c->coreStat = CORE_STAT_STOPING;
			return AE_NOMORE;
		}
	}
	return 100; /* every 100ms */
}
///////
struct core* initCore(int workThreadNum, int serverNum) {
	workThreadNum = workThreadNum > 0 ? workThreadNum : 1;
	serverNum = serverNum > 0 ? serverNum : 1;

	struct core* c = NULL;
	if ( !(c = zcalloc(sizeof(struct core)))) {
		mylog(LOG_WARNING, "zcalloc core error!!!");
		return NULL;
	}

	if (! (c->serverList = (struct server**)zcalloc(sizeof(struct server* ) * serverNum))) {
		mylog(LOG_WARNING, "zcalloc core server list error!!!");
		zfree(c);
		return NULL;
	}
	c->serverNum = serverNum;

	if (! (c->workThreadList = (struct thread**)zcalloc(sizeof(struct thread*)  * workThreadNum)) ) {
		mylog(LOG_WARNING, "zcalloc core work thread list error!!!");
		zfree(c->serverList);
		zfree(c);
		return NULL;
	}
	c->workThreadNum = workThreadNum;

	if (initThreadPool(c) == INIT_THREADPOOL_ERROR) {
		mylog(LOG_WARNING, "init thread pool error!!!");
		zfree(c->workThreadList);
		zfree(c->serverList);
		zfree(c);
		return NULL;
	}

	c->nextServerId = 0;
	c->nextWorkThreadId = 0;

	c->eventLoop = aeCreateEventLoop();
	if (! c->eventLoop) {
		mylog(LOG_WARNING, "create core eventLoop error!!!!");
		destroyThreadPool(c);
		zfree(c->workThreadList);
		zfree(c->serverList);
		zfree(c);
		return NULL;
	}

	aeCreateTimeEvent(c->eventLoop,
										1,
										coreCron,
										c,
										NULL);

    c->coreStat = CORE_STAT_INIT;
    mylog(LOG_INFO, "init core success, server num[%d], next server id[%d], work thread num[%d]!!!", c->serverNum, c->nextServerId, c->workThreadNum);
	return c;
}

void destroyCore(core* c) {
	if (!c) {
		return;
	}

	destroyThreadPool(c);
	aeDeleteEventLoop(c->eventLoop);
	zfree(c->workThreadList);
	zfree(c->serverList);
	zfree(c);
	mylog(LOG_INFO, "destroy core success!!!");
	return;
}

void stopCore(core* c){
	if (! c) {
		return;
	}

    c->coreStat = CORE_STAT_STOP;
	mylog(LOG_INFO, "stop coreing!!!");

	int i;
	for (i = 0; i < c->workThreadNum; i++) {
		stopThreadEvent(c->workThreadList[i]);
	}
	mylog(LOG_INFO, "stop core end!!!");
}

int addServerCore(core*c, server* s) {
	if (!c || !s) {
		mylog(LOG_WARNING, "add server error !!!");
		return CORE_ERR;
	}

	if (c->nextServerId >= c->serverNum) {
		mylog(LOG_WARNING, "too much server, max server num[%d], cur server num[%d] !!!", c->serverNum, c->nextServerId);
		return CORE_ERR;
	}

	c->serverList[c->nextServerId++] = s;
	return 0;
}

void removeServerCore(struct core* c, struct server* s) {
	if (!c || !s) {
		mylog(LOG_WARNING, "remove server error!!!");
		return;
	}

	int i;
	int pos = -1;
	for (i = 0; i < c->nextServerId; i++) {
		struct server* tmp = (struct server* )c->serverList[i];
		if (tmp) {
			if (tmp->id == s->id) {
				pos = i;
				break;
			}
		}
	}

	if (pos != -1) {
		memmove((void*)c->serverList + pos, (void*)c->serverList + pos + 1, sizeof(struct server*) * (c->nextServerId - pos - 1));
	}
}

void eventLoopCore(core* c) {
	if (!c) {
		mylog(LOG_WARNING, "core event loop error!!!");
		return;
	}

	if (!c->eventLoop) {
		mylog(LOG_WARNING, "core event loop is null!!!");
		return;
	}

	mylog(LOG_INFO, "core in event loop!!!\n");
    c->coreStat = CORE_STAT_RUN;
	aeMain(c->eventLoop);
	mylog(LOG_INFO, "end core in event loop end!!!\n");
	return;
}

void dispathWorkThread(core* c, void* session) {
	if (!c) {
		return;
	}

	int nextWorkThreadId = c->nextWorkThreadId++ % c->workThreadNum;
	if (! c->workThreadList[nextWorkThreadId]) {
		c->nextWorkThreadId = 0;
		return;
	}

	c->nextWorkThreadId = nextWorkThreadId + 1;
	mylog(LOG_INFO, "next work thread id[%d]", c->nextWorkThreadId);

	pushMsgQueueEvent(c->workThreadList[nextWorkThreadId], session);
}
